#
# this is a more complicated test hatchling
#

# which looks like it wants to hatch a register block.

from hatch_register import RegisterBlock, Pack, Register

hatchBlock = RegisterBlock(name='timers', target='small apb slave',
                          input_ports="""digital_domain_valid, tick_32k,
                          ao_freeze_time, force_awake_state_set""",
                          output_ports="""tick_1ms_o, tick_16ms_o, tick_64ms_o,
                          pulsecomp_tick_source_0, pulsecomp_tick_source_1,  pulsecomp_tick_source_2, pulsecomp_tick_source_3,
                          pulsecomp_tick_source_4, pulsecomp_tick_source_5,  pulsecomp_tick_source_6,
                          watchdog_timer_reset,
                          timer_a_state_set,
                          timer_b_state_set,
                          timer_c_state_set,
                          timer_pulsecomp_state_set""",
                          prefix="test_b_")

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

hatchBlock.Register('real_time_clock_low_word', width=32, sw='rw',
                   comment="""This is the low 32 bits of the 48 bit
                   real time clock counter.  This is incremented at a
                   rate of 32kHz""", auto='i', auto_inc_on='tick_32k',
                   rollover=1, 
                   rtl="""
  wire [7:0] tick_source = {(~real_time_clock_low_word[23] &
                             real_time_clock_low_word_next[23]),
                            (~real_time_clock_low_word[19] &
                             real_time_clock_low_word_next[19]),
                            (~real_time_clock_low_word[15] &
                             real_time_clock_low_word_next[15]),
                            (~real_time_clock_low_word[11] &
                             real_time_clock_low_word_next[11]),
                            (~real_time_clock_low_word[ 8] &
                             real_time_clock_low_word_next[ 8]),
                            (~real_time_clock_low_word[ 6] &
                             real_time_clock_low_word_next[ 6]),
                            (~real_time_clock_low_word[ 4] &
                             real_time_clock_low_word_next[ 4]),
                            (~real_time_clock_low_word[ 3] &
                             real_time_clock_low_word_next[ 3])};

  // tick_1ms_o is already decalred as a wire because it's an output port
  // for this module.
  assign tick_1ms_o = tick_source[1];

  // tick_16ms_o is already decalred as a wire because it's an output port
  // for this module.
  assign tick_16ms_o = tick_source[3];

  // tick_64ms_o is already decalred as a wire because it's an output port
  // for this module.
  assign tick_64ms_o = ~real_time_clock_low_word[12] &
                        real_time_clock_low_word_next[12];

  // renamed tick source signals that are sent to the poulseocmp logic
  assign pulsecomp_tick_source_0 = tick_source[0];
  assign pulsecomp_tick_source_1 = tick_source[1];
  assign pulsecomp_tick_source_2 = tick_source[2];
  assign pulsecomp_tick_source_3 = tick_source[3];
  assign pulsecomp_tick_source_4 = tick_source[4];
  assign pulsecomp_tick_source_5 = tick_source[5];
  assign pulsecomp_tick_source_6 = tick_source[6];
""")

hatchBlock.Register('real_time_clock_high_word', width=16, sw='rw',
                   comment="""This is the high 16 bits of the 48 bit
                   real time clock counter.""",
                   auto='i', auto_inc_on="""((real_time_clock_low_word == 32'hffffffff) & tick_32k)""",
                   rollover=1)

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

hatchBlock.Pack('watchdog_timer_pack',

    # this register generates a signal in the hardware called
    # watchdog_key_trigger when the key value is written to it.
    Register('watchdog_key', width=12,
             comment="""0x71d=enable the watchdog timer
             value to be written by software.  All other
             values written to this register have no side
             effects.""", key_value=0x71d, sw='t', trigger_count=16),

    # software write is only enabled to this register when
    # watchdog_key_trigger is also asserted at the same time. this
    # registers generates a watchdog_timer_trigger value when the
    # value goes from nonzero to zero.  It is also an automaticaly
    # generated down counter that rolls over. When it rolls over it
    # reloads the default value.

    Register('watchdog_timer', width=20, comment="""This
            counter decrements at a rate determined by the
            watchdog_timer_tick_source register. If this
            counter reaches zero, the CPU is reset and the
            counter rolls over to a value of 0xfffff. When
            force_awake or freeze_time is asserted this
            counter does not decrement.""",
            
            auto='d', auto_dec_on='watchdog_timer_tick & ~(ao_freeze_time & digital_domain_valid)',
            sw='rw', default=0xfffff, rollover=1,
            sw_load_enable='watchdog_key_trigger'),
                
    wire='watchdog_timer_tick',
                
    rtl="""
  assign watchdog_timer_tick = tick_source[watchdog_timer_tick_source] &
                               ~force_awake_state_set;\n
""")

hatchBlock.Register('watchdog_timer_reset', width=1,
                    default="(watchdog_timer == 20'd0) & watchdog_timer_tick",
                    sw='rw')

hatchBlock.Pack('watchdog_tick_source_pack',

    Register('watchdog_tick_key', width=28,
            key_value=0x7a551e5, sw='t',
            comment="""Writing 0x7a551e5 will enable the
            watchdog timer tick source to be written by
            software.  All other values written to this
            register have no side effects."""),

    Register('watchdog_timer_tick_filler', width=1, sw='r',
            comment="""this is a dummy bit to pad this
            pack."""),

    Register('watchdog_timer_tick_source', width=3,
            comment="""this determins the frequency
            with which the watchdog_timer will be
            decremented. i.e. it is used to select a
                bit position from the RTC counter as the
                toggle source. <ul>
                <li>0 = 2K Hz.
                <li>1 = 1KHz.
                <li>2 = 256 Hz.
                <li>3 = 64 Hz.
                <li>4 = 8 Hz.
                <li>5 = 1/2 Hz.
                <li>6 = 1/32 Hz.
                <li>7 = 1/512 Hz.
                </ul> Note that K=1024 in this context.""",
            sw_load_enable='watchdog_tick_key_trigger',
            sw='rw', default=4)
    )

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

for t in ['a', 'b', 'c', 'pulsecomp']:

    hatchBlock.Register('timer_%s_enable'%(t), width=1,
            comment="""1=enable this counter.  When
            software writes a 1 to this register the
            counter starts counting down on the next tick.
            If the current counter value is zero when this
            is enabled, the the preset value is loaded on
            the next tick and a timer event is
            generated. If the preset value is zero when the
            timer counts down to zero, this bit is
            automaticaly cleared, this provides one shot
            timer functionality.""", sw='rw', auto='c',

            auto_clear_on="""timer_%s_tick & (timer_%s_preset == 14'd0) & (timer_%s == 14'd0)"""%(t,t,t)),
                
    hatchBlock.Register('timer_%s_tick_source'%(t), width=3,
            comment="""this determins the frequency
            with which timer %s will be
            decremented. i.e. it is used to select a
            bit position from the RTC counter as the
            toggle source. <ul>
            <li>0 = 2K Hz.
            <li>1 = 1KHz.
            <li>2 = 256 Hz.
            <li>3 = 64 Hz.
            <li>4 = 8 Hz.
            <li>5 = 1/2 Hz.
            <li>6 = 1/32 Hz.
            <li>7 = 1/512 Hz.
            </ul> Note that K=1024 in this context."""%(t),
            sw='rw'),

    hatchBlock.Register('timer_%s_preset'%(t), width=14,
            comment="""this is the value that will be
            loaded into timer %s when it counts down to 0.
            If this value is 0 when the timer counts down
            to 0, the timer is dissabled."""%(t), sw='rw'),
    
    hatchBlock.Register('timer_%s'%(t), width=14, comment="""This is a
            14 bit down counter which reloads the preset
            value when it reaches zero.  The counter is
            decremented by a programable tap from the
            master real time clock counter. When
            freeze_time is asserted or this counter is not
            enabled, this counter does not decrement. When
            this counter values transitions from a non zero
            value to a zero value, an interrupt or wake
            event will be triggered.  This transition can be
            trigered when software writes a zero value to
            this counter while it contains a non zero value
            and the counter is enabled.""",
            auto='d', auto_dec_on='timer_%s_tick & timer_%s_enable'%(t, t),
            rollover=1, sw='rw',
            default='timer_%s_preset'%(t),
            wire="timer_%s_tick"%(t),
            rtl="""
  assign timer_%s_tick = tick_source[timer_%s_tick_source] &
                         ~(ao_freeze_time & digital_domain_valid);
  assign timer_%s_state_set = timer_%s_tick &
                                     timer_%s_enable &
                                     (timer_%s == 14'd0);\n"""%(t,t,t,t,t,t))
    

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

